package com.sweet.date;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期时间工具类
 *
 * @author limi
 * @version 2016-06-29
 */
public final class DateTimeUtil {
    /**
     * 定义格式化模板缓存
     */
    private DateTimeUtil() {
    }

    /**
     * 获取unix当前时间戳，单位秒
     * 指当前时间距离1970-01-01:00:00:00 UTC的时间戳，每个时区都一样
     *
     * @return
     */
    public static int getUnixTimestamp() {
        return (int) (System.currentTimeMillis() / 1000);
    }

    /**
     * 获取unix当前时间戳，单位秒
     * 指当前时间距离1970-01-01:00:00:00 UTC的时间戳，每个时区都一样
     *
     * @param date
     * @return
     */
    public static int getUnixTimestamp(Date date) {
        return (int) (date.getTime() / 1000);
    }

    /**
     * 获取unix当前时间戳，单位秒
     * 指当前时间距离1970-01-01:00:00:00 UTC的时间戳，每个时区都一样
     *
     * @param calendar
     * @return
     */
    public static int getUnixTimestamp(Calendar calendar) {
        return (int) (calendar.getTimeInMillis() / 1000);
    }


    /**
     * 获取字符串时间获取当前时间戳，单位秒
     * 指当前时间距离1970-01-01:00:00:00 UTC的时间戳，每个时区都一样
     *
     * @param datetime 日期,格式：yyyy-MM-dd HH:mm:ss
     * @param timeZone 时区
     * @return
     */
    public static int getUnixTimestamp(String datetime, TimeZone timeZone) throws ParseException {
        return getUnixTimestamp(parseDateTime(datetime, timeZone));
    }

    /**
     * 转换时间戳为时间
     *
     * @param unixTimeStamp 秒，乘以1000之前必须*1l转为long型
     * @return new Date(毫秒),其中毫秒表示GMT时间1970年1月1日至今的毫秒数
     */
    public static Date parseUnixTimeStamp(int unixTimeStamp) {
        return parseUnixTimeStampInMillis(1L * unixTimeStamp * 1000);
    }

    /**
     * 转换时间戳为时间
     *
     * @param millis 毫秒
     * @return new Date(毫秒),其中毫秒表示GMT时间1970年1月1日至今的毫秒数
     */
    public static Date parseUnixTimeStampInMillis(long millis) {
        return new Date(millis);
    }

    /**
     * 将日期跨时区转换
     *
     * @param datetime       字符串时间
     * @param pattern        格式化样式
     * @param sourceTimeZone 字符串时间所属时区
     * @param toTimeZone     字符串目标时区
     * @return
     * @throws ParseException
     */
    public static String convert(String datetime, String pattern, TimeZone sourceTimeZone, TimeZone toTimeZone) throws ParseException {
        //获取原时区时间
        Date sourceDate = parse(datetime, pattern, sourceTimeZone);

        //格式化时间
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        format.setTimeZone(toTimeZone);
        return format.format(sourceDate);
    }

    /**
     * 转换字符串为当前系统时区日期
     *
     * @param datetime 字符串时间
     * @param pattern  格式化样式
     * @param timeZone 字符串时间所属时区
     * @return
     * @throws ParseException
     */
    public static Date parse(String datetime, String pattern, TimeZone timeZone) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        format.setTimeZone(timeZone);
        return format.parse(datetime);
    }

    /**
     * 格式化日期
     *
     * @param date     字符串日期
     * @param timeZone 字符串日期所属时区
     * @return yyyy-MM-dd
     * @throws ParseException
     */
    public static Date parseDate(String date, TimeZone timeZone) throws ParseException {
        return parse(date, TimeFormatPattern.DATE.getPattern(), timeZone);
    }

    /**
     * 格式化日期
     *
     * @param time     字符串时间
     * @param timeZone 字符串时间所属时区
     * @return HH:mm:ss
     * @throws ParseException
     */
    public static Date parseTime(String time, TimeZone timeZone) throws ParseException {
        return parse(time, TimeFormatPattern.TIME.getPattern(), timeZone);
    }

    /**
     * 格式化日期
     *
     * @param date
     * @return yyyy-MM-dd HH:mm:ss
     * @throws ParseException
     */
    public static Date parseDateTime(String date, TimeZone timeZone) throws ParseException {
        return parse(date, TimeFormatPattern.DATE_TIME.getPattern(), timeZone);
    }

    /**
     * 格式化日期
     *
     * @param date    日期
     * @param pattern 格式化样式
     */
    public static String format(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 格式化为日期
     *
     * @param date
     * @return yyyy-MM-dd
     */
    public static String formatDate(Date date) {
        return format(date, TimeFormatPattern.DATE.getPattern());
    }

    /**
     * 格式化日期
     *
     * @param date
     * @return HH:mm:ss
     */
    public static String formatTime(Date date) {
        return format(date, TimeFormatPattern.TIME.getPattern());
    }

    /**
     * 格式化为日期
     *
     * @param date
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String formatDateTime(Date date) {
        return format(date, TimeFormatPattern.DATE_TIME.getPattern());
    }

    /**
     * 获取当前日期
     *
     * @return yyyy-MM-dd
     */
    public static String getCurrentDate() {
        return formatDate(new Date());
    }

    /**
     * 获取当前时间
     *
     * @return HH:mm:ss
     */
    public static String getCurrentTime() {
        return formatTime(new Date());
    }

    /**
     * 获取当前日期时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getCurrentDateTime() {
        return formatDateTime(new Date());
    }

    /**
     * 获取星期，从周1开始排
     *
     * @return
     */
    public static int getCurrentWeekOrderMonday() {
        // Calendar.DAY_OF_WEEK从周日开始，周日=1，周一=2....周六=7
        int week = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);

        //改为从周1开始，周一=1....周日=7
        return week == Calendar.SUNDAY ? 7 : week - 1;
    }

    /**
     * 获取当前小时
     *
     * @param is24 是否为24小时制度
     * @return
     */
    public static int getCurrentHour(boolean is24) {
        Calendar can = Calendar.getInstance();
        return is24 ? can.get(Calendar.HOUR_OF_DAY) : can.get(Calendar.HOUR);
    }

    /**
     * 获取当前时间
     *
     * @param day
     * @return
     */
    public static Date getCurrentTime(int day) {
        //获取今天
        if (day == 0) {
            return new Date();
        }

        //使用日历计算
        Calendar can = Calendar.getInstance();
        can.add(Calendar.DATE, day);
        return can.getTime();
    }

    /**
     * 获取今日开始时间
     *
     * @return
     */
    public static Date getTodayStart() {
        return getStartTime(0);
    }

    /**
     * 获取今日结束时间
     *
     * @return
     */
    public static Date getTodayEnd() {
        return getEndTime(0);
    }

    /**
     * 获取当前时间下，指定日期的开始时间
     *
     * @param day
     * @return
     */
    public static Date getStartTime(int day) {
        return getStartTime(getUnixTimestamp(), day);
    }

    /**
     * 获取指定日期，指定日期的开始时间
     *
     * @param date 日期
     * @param day  天数
     * @return
     */
    public static Date getStartTime(Date date, int day) {
        return getStartTime(getUnixTimestamp(date), day);
    }

    /**
     * 获取指定时间戳，指定日期的开始时间
     *
     * @param unixTimestamp 时间戳，秒
     * @param day
     * @return
     */
    public static Date getStartTime(int unixTimestamp, int day) {
        //获取日历
        Calendar can = getCalendar(unixTimestamp, day);

        //重置为起始时间
        initStart(can);

        return can.getTime();
    }

    /**
     * 初始化为开始时间
     *
     * @param unixTimestamp 时间戳，秒
     * @return
     */
    public static Date initStartTime(int unixTimestamp) {
        return getStartTime(unixTimestamp, 0);
    }

    /**
     * 获取当前时间下，指定日期的结束时间
     *
     * @param day 天数
     * @return
     */
    public static Date getEndTime(int day) {
        return getEndTime(getUnixTimestamp(), day);
    }

    /**
     * 获取指定日期，指定日期的结束时间
     *
     * @param date 日期
     * @param day  天数
     * @return
     */
    public static Date getEndTime(Date date, int day) {
        return getEndTime(getUnixTimestamp(date), day);
    }

    /**
     * 获取指定时间戳，指定日期的结束时间
     *
     * @param unixTimestamp 时间戳，秒
     * @param day           天数
     * @return
     */
    public static Date getEndTime(int unixTimestamp, int day) {
        //获取日历
        Calendar can = getCalendar(unixTimestamp, day);

        //重置为起始时间
        initEnd(can);

        return can.getTime();
    }

    /**
     * 获取日历
     *
     * @param unixTimestamp 时间戳，秒
     * @param day           天数
     * @return
     */
    private static Calendar getCalendar(int unixTimestamp, int day) {
        //获取日历
        Calendar can = Calendar.getInstance();

        //设置基准日期
        long millis = unixTimestamp * 1000L;
        if (can.getTimeInMillis() != millis) {
            can.setTimeInMillis(millis);
        }

        //调整日期
        if (day != 0) {
            can.add(Calendar.DATE, day);
        }

        return can;
    }

    /**
     * 初始化为结束时间
     *
     * @param unixTimestamp unix时间戳，秒
     * @return
     */
    public static Date initEndTime(int unixTimestamp) {
        return getEndTime(unixTimestamp, 0);
    }

    /**
     * 基于当前时间，获取指定日期月初
     *
     * @param unixTimestamp 时间戳(秒)
     * @return
     */
    public static Date getMonthStartTime(int unixTimestamp) {
        //定义日历
        Calendar can = Calendar.getInstance();

        //设置基准日期
        long millis = unixTimestamp * 1000L;
        if (can.getTimeInMillis() != millis) {
            can.setTimeInMillis(millis);
        }

        //设置为本月1号
        can.set(Calendar.DATE, 1);

        //重置为起始时间
        initStart(can);

        return can.getTime();
    }

    /**
     * 获取指定日期月末
     *
     * @param unixTimestamp 时间戳(秒)
     * @return
     */
    public static Date getMonthEndTime(int unixTimestamp) {
        //定义日历
        Calendar can = Calendar.getInstance();

        //设置基准日期
        long millis = unixTimestamp * 1000L;
        if (can.getTimeInMillis() != millis) {
            can.setTimeInMillis(millis);
        }

        //设置为本月月底
        can.set(Calendar.DATE, can.getActualMaximum(Calendar.DATE));

        //重置为结束时间
        initEnd(can);

        return can.getTime();
    }

    /**
     * 基于当前时间，获取指定日期月初
     *
     * @param time
     * @return
     */
    public static Date getMonthStartTime(Date time) {
        return getMonthStartTime(getUnixTimestamp(time));
    }

    /**
     * 获取指定日期月末
     *
     * @param time
     * @return
     */
    public static Date getMonthEndTime(Date time) {
        return getMonthEndTime(getUnixTimestamp(time));
    }

    /**
     * 初始化为开始时间
     *
     * @param calendar
     */
    public static void initStart(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
    }

    /**
     * 初始化为结束时间
     *
     * @param calendar
     */
    public static void initEnd(Calendar calendar) {
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
    }

    /**
     * 获取两个日期包含的日期列表
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return
     */
    public static List<Date> getDates(Date start, Date end) {
        //验证日期是否正常
        if (start == null || end == null || end.getTime() < start.getTime()) {
            return null;
        }

        //定义起始日历，初始化时分秒为23:59:59
        Calendar startCan = Calendar.getInstance();
        startCan.setTime(start);
        initStart(startCan);

        //定义结束日历
        Calendar endCan = Calendar.getInstance();
        endCan.setTime(end);
        endCan.add(Calendar.DATE, 1);
        initStart(endCan);

        //定义日期列表
        List<Date> dates = new ArrayList<>();
        while (startCan.before(endCan)) {
            //保存日期
            dates.add(startCan.getTime());

            //日期+1
            startCan.add(Calendar.DATE, 1);
        }

        return dates;
    }

    public static Date getLastDate(int day) {
        Calendar nowCan = Calendar.getInstance();
        nowCan.set(Calendar.HOUR_OF_DAY, 0);
        nowCan.set(Calendar.MINUTE, 0);
        nowCan.set(Calendar.SECOND, 0);
        nowCan.set(Calendar.MILLISECOND, 0);

        nowCan.add(Calendar.DATE, -day + 1);

        return nowCan.getTime();
    }
//
//    /**
//     * 判断指定时间是否在本月1号之前
//     *
//     * @param datetime
//     * @return
//     */
//    public static boolean isLastMonth(long datetime) {
//        Calendar can = Calendar.getInstance();
//
//        // 设置为本月初
//        can.set(Calendar.DATE, 1);
//
//        // 重置为起始时间
//        initStart(can);
//
//        return datetime - can.getTimeInMillis() < 0;
//    }
//
//    /**
//     * 获取指定日期的当天起始时间
//     *
//     * @return
//     */
//    public static int getLastStart(int day) {
//        return (int) (getLastDate(day).getTime() / 1000);
//    }
}